#include "netdisk.h"

// 实现 ls 命令，用于列出目录内容！！！！！！
// path：要列出信息的目录路径
// result：用于存储最终结果的字符串
void get_all_info(char *path, char *result, int ntfd)
{
    // 打开一个目录
    DIR *dir = opendir(path);
    // 若是打开失败，将错误信息存储到result中，并返回
    if (dir == NULL)
    {
        char error[1024];
        memset(error, 0, sizeof(error));
        char e1[] = "The address \"";
        char e2[] = "\" does not exist.\n";
        strcat(error, e1);
        strcat(error, path);
        strcat(error, e2);
        strcat(result, error);
        return;
    }

    // 构造目录信息，在result中添加目录路径的标题信息 
    struct dirent *fileinfo;
    char dd[] = "DIRECTORY : ";
    strcat(result, dd);   // result:DIRECTORY：
    strcat(result, path); // 若是无参，则将当前工作目录路径放入到path中
    strcat(result, "\n"); 
    strcat(result, "*************************************************************\n");
    char dn[] = "File Name = "; // 文件名
    char dt[] = "File Type = "; // 文件类型

    // 使用readdir遍历目录中的所有文件和目录，获取每个条目的名称和类型
    // 之所以循环+readdir就可以读出全部信息，是因为当前读写位置pos在改变
    while ((fileinfo = readdir(dir)) != NULL)
    {
        strcat(result, dn);
        strcat(result, fileinfo->d_name); // 文件名加入到result结果中
        // 根据文件名的长度，添加不同数量的制表符 \t ，以对齐输出
        if (strlen(fileinfo->d_name) < 4)
        {
            strcat(result, "\t\t\t");
        }
        else if (strlen(fileinfo->d_name) >= 4 && strlen(fileinfo->d_name) < 12)
        {
            strcat(result, "\t\t");
        }
        else if (strlen(fileinfo->d_name) >= 12 && strlen(fileinfo->d_name) < 20)
        {
            strcat(result, "\t");
        }
        strcat(result, dt);
        if (fileinfo->d_type == DT_UNKNOWN) // 如果文件为位置类型
        {
            strcat(result, "unknow type");
        }
        else if (fileinfo->d_type == DT_REG) // 若文件类型为普通文件
        {
            strcat(result, "regular file");
        }
        else if (fileinfo->d_type == DT_DIR) // 若是文件类型为目录
        {
            strcat(result, "directory file");
        }
        else if (fileinfo->d_type == DT_FIFO) // 若是文件为管道
        {
            strcat(result, "pipe file");
        }
        else if (fileinfo->d_type == DT_SOCK) // 若文件为套接字
        {
            strcat(result, "socket file");
        }
        else if (fileinfo->d_type == DT_CHR) // 若是文件为字符设备文件
        {
            strcat(result, "character device file");
        }
        else if (fileinfo->d_type == DT_BLK) // 若是文件为块设备
        {
            strcat(result, "block device File");
        }
        // 如果栈中只有一个元素（根目录），则不进行任何操作
        else if (fileinfo->d_type == DT_LNK) // 若是文件为链接文件
        {
            strcat(result, "link file");
        }

        strcat(result, "\n");
    }
    strcat(result, "*************************************************************\n");
}


// 根据用户输入的参数（如果有）列出目录中的问价和子目录信息
// char *arg：用户输入的参数，可以是目录路径或空
// int netfd：网络文件描述符
// Stack *dir：栈结构，用于存储当前工作目录的路径
void ls_fun(char *arg, int ntfd, Stack_t *dir)
{
    // 变量声明
    char result[8192]; //-用于存储最终结果
    char path[256];    //-用于存储目录的位置

    // 判断是否无参
    if (arg == NULL) //-无参
    {
        // 若是无参，则调用travel_stack函数讲当前工作目录的路径存储到path中
        travel_stack(*dir, path);
        // 调用get_all_info函数获取当前目录的信息并存储到result中
        get_all_info(path, result, ntfd);
    }
    else //-有参
    {
        // 判断是是几个参数
        char *cur = arg;      // 指向用户输入参数的当前字符
        char args[100][1024]; //-i=行，j=列  用于存储解析后的多个参数
        memset(args, 0, sizeof(args));
        int i = 0;  // 当前参数的索引（即第几个参数）
        int j = 0;  // 当前参数的字符索引（即当前参数的第几个字符）
        // 三个变量用于标记是否遇到空格和字符
        bool meetspace = 0;
        bool meetcharacter_1 = 0;
        bool meetcharacter_2 = 0;
        // 通过循环和标志变量，解析用户输入的路径字符串，将其分割成多个参数
        while (*cur != '\0')
        {
            // 此时参数结束，则开始处理下一个参数
            if (meetspace && meetcharacter_1 && meetcharacter_2)
            {
                i++;
                j = 0;
                meetcharacter_1 = 0;
                meetcharacter_2 = 0;
                meetspace = 0;
            }
            // 如果当前字符是空格
            // 跳过空格
            // 如果之前已经遇到字符（meetcharacter_1 == 1）,则表示meetspace为1，表示当前参数已经结束
            else if (isspace(*cur)) 
            {
                cur++; 
                if (meetcharacter_1 == 1)
                {
                    meetspace = 1;
                }
            }
            // 如果当前字符不是空格
            else
            {
                if (meetspace == 1)
                {
                    meetcharacter_2 = 1;
                    continue;
                }
                args[i][j] = *cur;
                j++;
                cur++;
                meetcharacter_1 = 1;
            }
        }
        // i是几，就说明是j+1个参数

        // 处理多个参数 ls zsk/Linux
        for (int line = 0; line <= i; line++)
        {
            char real_path[4096];
            memset(real_path, 0, sizeof(real_path));
            char *cur = args[line];

        // 对于每个参数，调用 onePath 函数将其转换为绝对路径，并存储到 real_path 中
            onePath(args[line], real_path, dir);
        // 然后调用 get_all_info 函数获取该路径下的文件和目录信息，并追加到result中
            get_all_info(real_path, result, ntfd);
            
        }
    }
    // 服务器发送给客户端的错误码
    int ret = 0;
    send(ntfd, &ret, sizeof(int), MSG_NOSIGNAL);
    // 发送result的长度以及内容给客户端
    int  result_length=strlen(result);
    send(ntfd, &result_length, sizeof(int), MSG_NOSIGNAL);
    send(ntfd, result, result_length, MSG_NOSIGNAL);
}
